home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Comm
/
AmiTCP30b2.lha
/
src
/
devs
/
agnet
/
agnet.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-25
|
22KB
|
892 lines
RCS_ID_C="$Id: agnet.c,v 4.8 1994/02/25 01:13:12 ppessi Exp $";
/*
* agnet.c --- agnet main program and arexx interface
*
* Author: ppessi <Pekka.Pessi@hut.fi>
*
* Copyright (c) 1993 OHT-AmiTCP/IP Group,
* Helsinki University of Technology, Finland.
* All rights reserved.
*
* Created : Sat Feb 20 18:30:59 1993 ppessi
* Last modified: Thu Oct 7 18:23:33 1993 ppessi
*
* $Log: agnet.c,v $
* Revision 4.8 1994/02/25 01:13:12 ppessi
* *** empty log message ***
*
* Revision 3.1 93/10/07 19:24:08 ppessi
* Release 2.1 version
*
* Revision 2.1 93/05/14 16:46:32 ppessi
* Release version.
*
* Revision 2.0 93/03/10 16:35:03 16:35:03 ppessi (Pekka Pessi)
* Prototype release.
*/
#include <string.h>
#include <stdarg.h>
#include <dos/dostags.h>
#include <dos/rdargs.h>
#include <intuition/intuition.h>
#include <rexx/storage.h>
#include <rexx/rxslib.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/utility_protos.h>
#include <clib/intuition_protos.h>
#ifdef __SASC
#include <pragmas/exec_sysbase_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#endif
#include "agnet.h"
#include "agnet_protos.h"
#include "agnet_rev.h"
#include "bases.h"
static ULONG init_arexx(VOID);
static VOID poll_arexx(VOID);
static VOID deinit_arexx(VOID);
/*
* We start as a CLI.
* Assembler stub routine does a MakeLibrary and
* initializes needed librarybases
*/
LONG ASM main(REG(a6)struct AgnetDevice *adb)
{
struct Process *proc;
struct IOSana2Req *io;
ULONG waitmask, rexxsignal, signals;
UBYTE devsignal;
UBYTE myname[sizeof(AGNETDEVNAME)+5];
AgnetDeviceBase = adb;
proc = (struct Process *)FindTask(0L);
/* Initialize the device base */
adb->ad_Device.lib_Node.ln_Pri = AGNET_DEV_PRI;
adb->ad_Device.lib_Node.ln_Type = NT_DEVICE;
adb->ad_Device.lib_Node.ln_Name = myname;
adb->ad_Device.lib_Version = VERSION;
adb->ad_Device.lib_Revision = REVISION;
adb->ad_Device.lib_IdString = VSTRING;
adb->ad_Task = (struct Task *)proc;
/* Set up our unit message port */
/* Attempt to allocate a signal bit for our Unit MsgPort. */
devsignal = AllocSignal(-1L);
if (devsignal == -1) {
return 20;
}
NewList(&adb->ad_MsgPort.mp_MsgList);
adb->ad_MsgPort.mp_SigBit = devsignal;
adb->ad_MsgPort.mp_SigTask = (struct Task *)proc;
adb->ad_MsgPort.mp_Flags = PA_SIGNAL;
/* Initialize our device base semafore */
InitSemaphore(&adb->ad_Lock);
InitLRandom();
#ifdef AGREXX
/* Initialize Arexx port */
rexxsignal = init_arexx();
#else
rexxsignal = 0;
#endif
/* OK, we are ready to add agnet.device to system */
{
int i, n = sizeof(AGNETDEVNAME) - 1;
strcpy(myname, AGNETDEVNAME);
Forbid();
for (i = 0; i < 9; i++) {
if (!FindName(&adb->ad_SysBase->DeviceList, myname))
break;
myname[n] = '.'; myname[n+1] = '1' + i; myname[n+2] = '\0';
}
AddDevice(adb);
Permit();
}
waitmask = (1<<devsignal) | rexxsignal | SIGBREAKF_CTRL_F ;
while (TRUE) {
signals = Wait(waitmask); /* wait for device command */
if (signals & SIGBREAKF_CTRL_F) {
if (DoExpunge(adb))
break;
}
while (io = (struct IOSana2Req *)GetMsg(&adb->ad_MsgPort))
PerformIO(io);
#ifdef AGREXX
if (signals & rexxsignal)
poll_arexx();
#endif
}
/* Clean up */
#ifdef AGREXX
deinit_arexx();
#endif
FreeSignal(devsignal);
return 0;
}
/* Local prototypes */
static LONG ParseConfig(struct AgnetDevUnit *, struct RDArgs *, STRPTR*);
static BOOL GetBitAddress(UBYTE *addr, UBYTE *string, LONG bitsize);
static char *SanaSprintf(register char *ap, int len);
static ULONG csprintf(struct CSource *buf, const char *fmt, ...);
#define CONFIG_ENV_TEMPLATE "ENV:SANA2/config%ld.agnet"
#define UNINITIALIZED 0xffffffff
/*
* ReadConfig
*
* Attempt to read in the driver's configuration file.
*
* The files are named by ENV:SANA2/agnet%d.config where %d is the decimal
* representation of the device's unit number.
*
* Return FALSE upon error.
*/
BOOL ReadConfig(struct AgnetDevUnit *adu)
{
UBYTE *fbuf = NULL;
UBYTE buff[40];
struct CSource csbuff = { NULL, sizeof(buff), 0L };
BPTR ConfigFile;
LONG offset, len;
BOOL ok = FALSE;
csbuff.CS_Buffer = buff;
/* This configures unit by default values */
adu->adu_HardwareType = UNINITIALIZED;
/* Create the name of our config file.. */
csprintf(&csbuff, CONFIG_ENV_TEMPLATE, (ULONG)adu->adu_UnitNum);
/* ...and open it. */
ConfigFile = Open(buff, MODE_OLDFILE);
if (!ConfigFile)
return TRUE;
len = (Seek(ConfigFile, 0L, 1), Seek(ConfigFile, 0L, 0));
if (len >= 0 && (fbuf = AllocMem(len+2, MEMF_PUBLIC))) {
Seek(ConfigFile, 0L, -1);
if (Read(ConfigFile, fbuf, len) == len) {
ok = TRUE;
fbuf[len] = '\n';
fbuf[len+1] = '\0';
}
}
Close(ConfigFile);
if (ok) {
struct RDArgs *rdargs = AllocDosObject(DOS_RDARGS, NULL);
STRPTR *errmsg;
if (rdargs) {
/* Remove Comment lines */
for (offset = 0; offset < len;) {
if (fbuf[offset] == '#')
while(fbuf[offset] != '\n')
fbuf[offset++] = ' ';
else
while(fbuf[offset++] != '\n');
fbuf[offset - 1] = ' '; /* remove linefeeds in file */
}
/* Add sentinel */
fbuf[len] = '\n';
rdargs->RDA_Source.CS_Buffer = fbuf;
rdargs->RDA_Source.CS_Length = len + 1;
rdargs->RDA_Source.CS_CurChr = 0;
if (ParseConfig(adu, rdargs, &errmsg)) {
struct EasyStruct es;
APTR args[2];
args[0] = errmsg;
args[1] = buff;
es.es_StructSize = sizeof(es);
es.es_Flags = 0;
es.es_Title = AGNETDEVNAME;
es.es_TextFormat="Error %s in \nthe configuration file\n%s";
es.es_GadgetFormat="Okay";
EasyRequestArgs(NULL, &es, 0, args);
ok = FALSE;
}
}
FreeDosObject(DOS_RDARGS, rdargs);
}
if (fbuf) FreeMem(fbuf, len+2);
return ok;
}
#define MYREXXNAME "agnet"
#define MYREXXEXTENSION "agnet"
/* Error strings */
#define ERR_MALFORMED "Malformed command line"
#define ERR_SYNTAX "Syntax error"
#define ERR_WIRE "Illegal wiretype"
#define ERR_ADDRESS "Illegal address"
#define ERR_UNIT "Illegal unit number"
#define ERR_INITUNIT "Error initializing unit"
#define ERR_MEMORY "Memory exhausted"
#define ERR_OPEN "Unit is currently opened"
#define ERR_VALUE "Illegal value"
#ifdef AGREXX
/*
* Arexx interface functions to agnet.device
*/
#include <rexx/storage.h>
#include <rexx/rxslib.h>
#include <clib/rexxsyslib_protos.h>
#ifdef __SASC
#include <pragmas/rexxsyslib_pragmas.h>
#endif
#include "SimpleRexx.h"
AREXXCONTEXT RexxContext;
static LONG ParseRexx(UBYTE *arg, UBYTE **errstr, UBYTE **result);
static LONG ParseQuery(struct AgnetDevUnit *, struct RDArgs *,
STRPTR *,STRPTR *);
/*
* Initialize Arexx port
*/
static ULONG
init_arexx(VOID)
{
ULONG rexxsignal;
RexxContext = InitARexx(MYREXXNAME, MYREXXEXTENSION);
if (!RexxContext)
return 0L;
rexxsignal = ARexxSignal(RexxContext);
return rexxsignal;
}
/*
* Free ARexx port
*/
static VOID
deinit_arexx(VOID)
{
if (RexxContext)
FreeARexx(RexxContext);
}
/*
* Poll Arexx port
*/
static VOID
poll_arexx(VOID)
{
struct RexxMsg *rmsg;
/*
* Process the ARexx messages...
*/
while (rmsg = GetARexxMsg(RexxContext)) {
UBYTE *error = NULL, *result = NULL;
LONG errlevel=0;
if (errlevel = ParseRexx(ARG0(rmsg), &error, &result)) {
SetARexxLastError(RexxContext, rmsg, error);
}
ReplyARexxMsg(RexxContext, rmsg, result, errlevel);
}
}
/*
* Rexx commands
*/
#define REXXKEYWORDS "U=UNIT,Q=QUERY,E=EXIT=EXPUNGE"
#define KEYWORDLEN 16
#define KEY_UNIT 0
#define KEY_QUERY 1
#define KEY_EXIT 2
/*
* Parse the ARexx command
*/
static LONG
ParseRexx(UBYTE *arg, UBYTE **errstr, UBYTE **result)
{
struct AgnetDevice *adb = AgnetDeviceBase;
LONG errlevel = 0;
UBYTE Buffer[KEYWORDLEN];
LONG len = LengthArgstring(arg) + 2;
UBYTE *cmd = AllocMem(len, 0);
struct RDArgs *rdargs = AllocDosObject(DOS_RDARGS, NULL);
LONG unit, keyword;
struct AgnetDevUnit *adu;
if (!cmd || !rdargs) {
errlevel = 40;
*errstr = ERR_MEMORY;
} else {
memcpy(cmd, arg, len - 2);
/* Add sentinel */
cmd[len-2] = '\n'; cmd[len-1] = '\0';
rdargs->RDA_Source.CS_Buffer = cmd;
rdargs->RDA_Source.CS_Length = len - 1;
rdargs->RDA_Source.CS_CurChr = 0;
/* First, parse the command keyword */
if (ReadItem(Buffer, sizeof(Buffer), &rdargs->RDA_Source) <= 0 ||
(keyword = FindArg(REXXKEYWORDS, Buffer)) < 0) {
errlevel = 20;
*errstr = ERR_MALFORMED;
} else {
switch (keyword) {
case KEY_UNIT:
case KEY_QUERY:
/* Parse unit number */
if ((len = StrToLong(cmd + rdargs->RDA_Source.CS_CurChr, &unit)) < 0 ||
unit >= AD_MAXUNITS) {
errlevel = 20;
*errstr = ERR_UNIT;
break;
}
rdargs->RDA_Source.CS_CurChr += len;
if (!(adu = adb->ad_Units[unit]))
/* If there is no opened unit, we init one */
if (keyword == KEY_QUERY || !(adu = InitUnit(unit))) {
/* We got no unit structure, there was an initialization
problem, we must give up */
*errstr = ERR_INITUNIT;
errlevel = 20;
break;
}
if (keyword == KEY_UNIT) {
/* Parse the rest of the line with ParseConfig */
errlevel = ParseConfig(adu, rdargs, errstr);
break;
} else {
errlevel = ParseQuery(adb->ad_Units[unit], rdargs, errstr, result);
break;
}
case KEY_EXIT:
/* We try to expunge */
SetSignal(SIGBREAKF_CTRL_F, SIGBREAKF_CTRL_F);
break;
}
}
}
if (cmd) FreeMem(cmd, len);
if (rdargs) FreeDosObject(DOS_RDARGS, rdargs);
return errlevel;
}
#endif /* AGREXX */
/*
* Configuration parameters
*/
#define CONFIG_ARGS 20 /* # of args in CONFIG_TEMPLATE */
#define CONFIG_TEMPLATE "WIRE/K" \
",MTU/N/K,MINTU/N/K,BPS/N/K,ADDR=ADDRESS/K" \
",DELAY/N/K,DEV=DEVIATION/N/K,ERRORS/K/N,LOSS/K/N,DST=DSTUNIT/N"
#define CMD_WIRE 0
#define CMD_MTU 1 /* Maximum transfer unit */
#define CMD_MINTU 2 /* Minimum Trransfer unit */
#define CMD_BPS 3 /* Bits per second */
#define CMD_ADDR 4 /* Address string */
#define CMD_DELAY 5 /* Delay in ms */
#define CMD_DEVIATION 6 /* Deviation in ms */
#define CMD_ERRORS 7 /* Bit error probability */
#define CMD_LOSS 8 /* Packet loss probability */
#define CMD_PPUNIT 9 /* Destination unit */
#define CMD_ALL 10 /* All values queried */
#define WIRE_TEMPLATE "LOOPBACK,ETHERNET,IEEE802,ARCNET" \
",LOCALTALK,AMOKNET" \
",PPP,SLIP,CSLIP" \
#define WIRE_LOOPBACK 0
#define WIRE_ETHERNET 1
#define WIRE_IEEE802 2
#define WIRE_ARCNET 3
#define WIRE_LOCALTALK 4
#define WIRE_AMOKNET 5
#define WIRE_PPP 6
#define WIRE_SLIP 7
#define WIRE_CSLIP 8
#ifdef AGREXX
#include <exec/initializers.h>
#define MAXQUERYLEN 512
#define QUERY_TEMPLATE "WIRE/S" \
",MTU/S,MINTU/S,BPS/S,ADDR=ADDRESS/S" \
",DELAY/S,DEV=DEVIATION/S,ERRORS/S,LOSS/S,DST=DSTUNIT/S,ALL/S"
static struct {
STRPTR title;
WORD offset;
enum { nulong, wire, address } type;
} query_titles[] = {
{ "WIRE", OFFSET(AgnetDevUnit, adu_HardwareType), wire },
{ "MTU", OFFSET(AgnetDevUnit, adu_MaxTU), nulong },
{ "MINTU", OFFSET(AgnetDevUnit, adu_MinTU), nulong },
{ "BPS", OFFSET(AgnetDevUnit, adu_BPS), nulong },
{ "ADDRESS", OFFSET(AgnetDevUnit, adu_Addr), address },
{ "DELAY", OFFSET(AgnetDevUnit, adu_Delay), nulong },
{ "DEVIATION",OFFSET(AgnetDevUnit, adu_Deviation), nulong },
{ "ERRORS", OFFSET(AgnetDevUnit, adu_Errors), nulong },
{ "LOSS", OFFSET(AgnetDevUnit, adu_Loss), nulong },
{ "DSTUNIT", OFFSET(AgnetDevUnit, adu_PPUnit), nulong }
};
#define AT_OFFSET(X,Y) ((UBYTE *)X + Y)
#define ULONG_AT(X,Y) (*(ULONG*)AT_OFFSET(X,Y))
static struct {
ULONG type;
STRPTR name;
} wirenames[] = {
{ S2WireType_LoopBack, "Loopback" },
{ S2WireType_Ethernet, "Ethernet" },
{ S2WireType_IEEE802, "IEEE802" },
{ S2WireType_Arcnet, "Arcnet" },
{ S2WireType_LocalTalk, "LocalTalk" },
{ S2WireType_AmokNet, "AmokNet" },
{ S2WireType_PPP, "PPP" },
{ S2WireType_SLIP, "SLIP" },
{ S2WireType_CSLIP, "CSLIP" },
{ S2WireType_LoopBack, "Unknown" }
};
#endif
/*
* Parse a configuration command
* adu = NULL if parse an ARexx command
* return differs from zero if an error
*/
static LONG
ParseConfig(struct AgnetDevUnit *adu, struct RDArgs *rdargs,
STRPTR *errormessage)
{
LONG args[CONFIG_ARGS] = {0};
LONG error;
LONG ppunit;
UBYTE address[MAX_ADDR_BYTES] = {0};
UWORD addrfieldsize;
ULONG hardwaretype, maxtu, mintu, bps, delay, deviation, errors, loss;
BOOL virgin;
LONG wire;
/* Parse the file or the line...*/
rdargs = ReadArgs(CONFIG_TEMPLATE, args, rdargs);
if (error = !rdargs) {
if (errormessage)
*errormessage = ERR_SYNTAX;
return error;
}
hardwaretype = adu->adu_HardwareType;
addrfieldsize = adu->adu_AddrFieldSize;
ppunit = adu->adu_PPUnit;
maxtu = adu->adu_MaxTU;
mintu = adu->adu_MinTU;
bps = adu->adu_BPS;
delay = adu->adu_Delay;
deviation = adu->adu_Deviation;
errors = adu->adu_Errors;
loss = adu->adu_Loss ;
memcpy(address, adu->adu_Addr, MAX_ADDR_BYTES);
virgin = hardwaretype == UNINITIALIZED;
if (args[CMD_WIRE]) {
wire = FindArg(WIRE_TEMPLATE, args[CMD_WIRE]);
} else if (virgin) {
wire = S2WireType_Ethernet;
}
if (args[CMD_WIRE] || virgin) {
switch (wire) {
case WIRE_LOOPBACK:
/* This is simple loopback type */
hardwaretype = S2WireType_LoopBack;
addrfieldsize = 0; /* No addresses */
maxtu = 1024;
bps = 100000000; /* it's fast like a hell...*/
mintu = 0;
/* There is no need for address but we zero it anyways */
memset(address, 0, MAX_ADDR_BYTES);
break;
case WIRE_ETHERNET:
/* This is default */
hardwaretype = S2WireType_Ethernet;
addrfieldsize = 48;
maxtu = 1500;
bps = 10000000; /* 10 Mb/s */
mintu = 1;
/* Ethernet address is same as unit number */
memset(address + 6, 0, MAX_ADDR_BYTES-2);
memcpy(address, "ETHER", 5);
address[5] = adu->adu_UnitNum;
ppunit = -1;
break;
case WIRE_IEEE802:
/* Wiretype is IEEE802 */
hardwaretype = S2WireType_IEEE802;
addrfieldsize = 48;
maxtu = 1500;
bps = 10000000; /* 10 Mb/s */
mintu = 1;
/* IEEE802 address is same as unit number */
memset(address+6, 0, MAX_ADDR_BYTES-6);
memcpy(address, "IEEE8", 5);
address[5] = adu->adu_UnitNum;
ppunit = -1;
break;
case WIRE_ARCNET:
hardwaretype = S2WireType_Arcnet;
addrfieldsize = 8;
maxtu = 506;
bps = 5000000L; /* 5 Mb/s */
mintu = 1;
/* Arcnet address is got from unit number */
memset(adu->adu_Addr, 0, MAX_ADDR_BYTES);
adu->adu_Addr[0] = 255 - adu->adu_UnitNum;
ppunit = -1;
break;
case WIRE_LOCALTALK:
/* Don't know much, but... */
hardwaretype = S2WireType_LocalTalk;
addrfieldsize = 8;
maxtu = 256;
bps = 128000L; /* 128 kb/s */
mintu = 1;
/* Localnet address is got from unit number */
memset(address, 0, MAX_ADDR_BYTES);
address[0] = adu->adu_UnitNum;
ppunit = -1;
break;
/* Amoknet parameters are all got with RaHi method */
case WIRE_AMOKNET:
/* Don't know much, but... */
hardwaretype = S2WireType_AmokNet;
addrfieldsize = 8;
maxtu = 512;
bps = 128000L; /* 128 kb/s */
mintu = 1;
/* Amoknet address is got from unit number */
memset(address, 0, MAX_ADDR_BYTES);
address[0] = adu->adu_UnitNum;
break;
case WIRE_PPP:
hardwaretype = S2WireType_PPP; goto serials;
case WIRE_SLIP:
hardwaretype = S2WireType_SLIP; goto serials;
case WIRE_CSLIP:
hardwaretype = S2WireType_CSLIP;
serials:
addrfieldsize = 32;
maxtu = 1006;
bps = 9600L; /* 9600 b/s */
mintu = 1;
/* SLIP address is set during config */
memset(address, 0, MAX_ADDR_BYTES);
break;
default:
if (errormessage)
*errormessage = ERR_WIRE;
error = 5;
goto free_and_exit;
}
}
if (args[CMD_MTU]) {
maxtu = *(ULONG *)args[CMD_MTU];
}
if (args[CMD_MINTU]) {
mintu = *(ULONG *)args[CMD_MINTU];
}
if (args[CMD_BPS]) {
bps = *(ULONG *)args[CMD_BPS];
}
if (args[CMD_ADDR]) {
memset(address, 0, MAX_ADDR_BYTES);
if (!GetBitAddress(address, (UBYTE *)args[CMD_ADDR], addrfieldsize)) {
if (errormessage)
*errormessage = ERR_ADDRESS;
error = 7;
goto free_and_exit;
}
}
if (args[CMD_DELAY]) {
delay = *(ULONG *)args[CMD_DELAY];
/* maximum delay is 0x800000 ms, that is fairly over an hour */
if (delay >= 0x800000)
delay = 0x7fffff;
}
if (args[CMD_DEVIATION]) {
deviation = *(ULONG *)args[CMD_DEVIATION];
}
if (args[CMD_ERRORS]) {
errors = *(ULONG *)args[CMD_ERRORS];
if (errors > ERRORS_MAX) {
error = 5;
*errormessage = ERR_VALUE;
goto free_and_exit;
}
}
if (args[CMD_LOSS]) {
loss = *(ULONG *)args[CMD_LOSS];
if (loss > LOSS_MAX) {
error = 5;
*errormessage = ERR_VALUE;
goto free_and_exit;
}
}
if (args[CMD_PPUNIT]) {
ppunit = *(ULONG *)args[CMD_PPUNIT];
}
if (!virgin) {
LockUnit(adu);
/*
* Changing the hardware type or reducing the MTU requires
* that the unit is not currently open
*/
if ((adu->adu_HardwareType != hardwaretype ||
adu->adu_MaxTU > maxtu) &&
adu->adu_Unit.unit_OpenCnt != 0 ) {
UnlockUnit(adu);
error = 5;
*errormessage = ERR_OPEN;
goto free_and_exit;
}
}
adu->adu_HardwareType = hardwaretype;
adu->adu_AddrFieldSize = addrfieldsize;
adu->adu_PPUnit = ppunit;
adu->adu_MinTU = mintu;
adu->adu_BPS = bps;
adu->adu_Delay = delay;
adu->adu_Deviation = deviation;
adu->adu_Errors = errors;
adu->adu_Loss = loss;
memcpy(adu->adu_Addr, address, MAX_ADDR_BYTES);
/*
* Enlarging the MTU requires offlining the device temporarily
*/
if (!virgin && adu->adu_MaxTU < maxtu) {
DoOffline(adu);
adu->adu_MaxTU = maxtu;
DoOnline(adu);
} else {
adu->adu_MaxTU = maxtu;
}
if (!virgin)
UnlockUnit(adu);
free_and_exit:
if (rdargs)
FreeArgs(rdargs);
return error;
}
#ifdef AGREXX
/*
* Parse Query Command
*/
static LONG
ParseQuery(struct AgnetDevUnit *adu,
struct RDArgs *rdargs,
STRPTR *errstr,
STRPTR *result)
{
LONG errlevel = 0;
LONG args[CONFIG_ARGS] = {0};
char res[MAXQUERYLEN];
struct CSource csres = { NULL, sizeof(res), 0L };
BOOL all;
LONG i;
csres.CS_Buffer = res;
/* Parse the file or the line...*/
rdargs = ReadArgs(QUERY_TEMPLATE, args, rdargs);
if (errlevel = !rdargs) {
*errstr = ERR_SYNTAX;
return errlevel;
}
all = args[CMD_ALL];
for (i = CMD_WIRE; i < CMD_ALL; i++)
if (all || args[i]) {
if (csres.CS_CurChr != 0 && csres.CS_CurChr < csres.CS_Length)
res[csres.CS_CurChr++] = ' ';
switch (query_titles[i].type) {
case nulong:
csprintf(&csres, "%s=%ld", query_titles[i].title,
ULONG_AT(adu, query_titles[i].offset));
break;
case wire:
{
int j; int type = ULONG_AT(adu, query_titles[i].offset);
for (j = 0; j < sizeof(wirenames)/sizeof(wirenames[0]) - 2; j++)
if (wirenames[j].type == type)
break;
csprintf(&csres, "%s=%s", query_titles[i].title,
wirenames[j].name);
}
break;
case address:
csprintf(&csres, "%s=%s", query_titles[i].title,
SanaSprintf(AT_OFFSET(adu,query_titles[i].offset),
adu->adu_AddrFieldSize + 7 >> 3));
break;
}
}
*result = CreateArgstring(res, csres.CS_CurChr);
if (!*result) {
*errstr = ERR_MEMORY;
return 40;
}
return errlevel;
}
#endif /* AGREXX */
/*
* Read hexadecimal address string into array.
*
* UBYTE *addr = address array
* UBYTE *string = hexadecimal address string,
* each byte sparated by colon (":")
* LONG bitsize = address length in bits
*
* Return true if no errors.
* If there is error, may trash the address.
*/
static BOOL
GetBitAddress(UBYTE *addr, UBYTE *string, LONG bitsize)
{
LONG bitsperbyte; UWORD next; UWORD chars;
UBYTE c;
memset(addr, 0, (bitsize + 7) >> 3);
while (bitsize > 0) {
bitsperbyte = bitsize < 8 ? bitsize : 8;
chars = next = 0;
while ((c = *string - '0') <= 9
|| (c = c - 'A' + '0' + 10) >= 9 && c < 16 /*ABCDEF*/
|| (c = c - 'a' + 'A') >= 9 && c < 16) /*abcdef*/ {
chars++; string++;
next = (next << 4) + c;
if (next >= 1 << bitsperbyte)
return FALSE;
}
if (!chars)
return FALSE;
*addr++ = next << (8 - bitsperbyte);
bitsize -= bitsperbyte;
if (*string != ':')
break;
string++;
}
if (bitsize || *string) return FALSE;
return TRUE;
}
/*
* Print Hardware Address
*/
static char *
SanaSprintf(register char *ap, int len)
{
const char *digits = "0123456789ABCDEF";
register i;
static char addrbuf[17*3];
register unsigned char *cp = addrbuf;
for (i = 0; i < len; ) {
*cp++ = digits[*ap >> 4];
*cp++ = digits[*ap++ & 0xf];
i++;
if (i < len)
*cp++ = ':';
}
*cp = 0;
return (addrbuf);
}
void ASM stuffchar(REG(d0) char ch, REG(a3) struct CSource * sc)
{
if (sc->CS_CurChr < sc->CS_Length
&& (sc->CS_Buffer[sc->CS_CurChr] = ch))
sc->CS_CurChr++;
}
static ULONG
csprintf(struct CSource *buf, const char *fmt, ...)
{
ULONG start = buf->CS_CurChr;
va_list ap;
va_start(ap, fmt);
RawDoFmt((STRPTR)fmt, ap, stuffchar, buf);
va_end(ap);
buf->CS_Buffer[buf->CS_CurChr] = '\0';
return buf->CS_CurChr - start;
}